// Max number of bone can be used
#define MaxBones 59

// -------- World Information
float4x4 World;
float4x4 View;
float4x4 Projection;
float4x4 WorldViewProj;
float4x4 WorldInverseTranspose;
float3 ViewVector;

float4x4 Bones[MaxBones];

// #region Light info
// -------- Ambient Light
float AmbientIntensity = 0.1f;
float4 AmbientColor = (1,1,1,1);

// -------- Direction Light 0
float3 LightDirection0 = (1,1,1);
float4 LightColor0 = (1.0,0,0,1.0);
float LightIntensity0 = 2.0f;

// -------- Direction Light 1
float3 LightDirection1 = (-1,-1,-1);
float4 LightColor1 = (1.0,0,0,1.0);
float LightIntensity1 = 1.0f;
// #endregion

texture DiffuseMap;
sampler DiffuseSampler = sampler_state
{
    Texture = (DiffuseMap);

    MinFilter = Linear;
    MagFilter = Linear;
    MipFilter = Linear;
};

// Struct for Vertext In/ouput
struct VertexInput
{
	float4 Position : POSITION0;
	float3 Normal : NORMAL0;
	float2 TexCoord : TEXCOORD0;
    float4 BoneIndices : BLENDINDICES0;
    float4 BoneWeights : BLENDWEIGHT0;	
};

struct VertexOutput
{
	float4 Position: POSITION;
	float3 Normal : TEXCOORD0;
	float2 TexCoord : TEXCOORD1;
};

VertexOutput VertexShaderFunction(VertexInput input)
{
    VertexOutput output;
    // Get the skin transformation
    // Blend the transformation with the weight
    float4x4 skinTransform = 0;
    
    skinTransform += Bones[input.BoneIndices.x] * input.BoneWeights.x;
    skinTransform += Bones[input.BoneIndices.y] * input.BoneWeights.y;
    skinTransform += Bones[input.BoneIndices.z] * input.BoneWeights.z;
    skinTransform += Bones[input.BoneIndices.w] * input.BoneWeights.w;
    
    float4 skinnedPosition = mul(input.Position, skinTransform);
    
    float4 worldPosition = mul(skinnedPosition, World);
    float4 viewPosition = mul(worldPosition, View);    
    output.Position = mul(viewPosition, Projection);
    
    output.TexCoord = input.TexCoord;
    
    // Compute the normal after scale and rotate, remove translation as it could cause lighting error
	float3 transNormal = mul(mul(input.Normal, WorldInverseTranspose), skinTransform);
	output.Normal = normalize(transNormal);

    return output;
}

float4 PixelShaderFunction(VertexOutput input) : COLOR0
{
	float4 texColor = tex2D(DiffuseSampler, input.TexCoord);
    return texColor;
}

/// ~~~~~~~~~~ This function will use the input normal to calculate the diffuse light factor
float4 CalculateLightFactor(float3 normal)
{
	// Calculate Light factor 0
	float4 lightFactor0 = 0;
	if(LightIntensity0 > 0)
	{
		float3 lightDir0 = normalize(LightDirection0);
		lightFactor0 = saturate(dot(normal, lightDir0)) * LightIntensity0 * LightColor0;
	}
	
	// Calculate Light factor 1
	float4 lightFactor1 = 0;
	if(LightIntensity1 > 0)
	{
		float3 lightDir1 = normalize(LightDirection1);
		lightFactor1 = saturate(dot(normal, lightDir1)) * LightIntensity1 * LightColor1;
	}
	
	// Calculate the diffuse light factor
	float4 DiffuseFactor = lightFactor0 + lightFactor1;	
	return DiffuseFactor;
}

technique StandardShader
{
    pass Pass1
    {
        VertexShader = compile vs_2_0 VertexShaderFunction();
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}
